<?php

/**
 * Dispatcher
 *
 */
class Rapide_Dispatcher implements Rapide_Dispatcher_Interface
{
	private
		$_oConfig,
		$_oToken;

	public function __construct()
	{
		$this->_oConfig = new Rapide_Config;
		$this->_oConfig->load('Controller.php');
	}

	/**
	 * Dispatch given token
	 *
	 * @param Rapide_Dispatcher_Token_Interface $oToken
	 * @return mixed token if has been returned by controller or false if not 
	 */
	public function execute(Rapide_Dispatcher_Token_Interface $oToken)
	{
		if(!$this->isDispatchable($oToken))
		{
			$s404Controller = $this->_oConfig->get('Controller', 'error', 'controller');
			$s404Action = $this->_oConfig->get('Controller', 'error', 'action', '404');

			$oToken = new Rapide_Dispatcher_Token($s404Controller, $s404Action);

			if(!$this->isDispatchable($oToken))
			{
				$sError = 'Action Error 404 does not exist';
				throw new Rapide_Dispatcher_Exception($sError);
			}
		}

		$this->_oToken = $oToken;
		
		$sControllersClass = $this->formatControllerName($oToken->getController());

		$oController = new $sControllersClass;
		$sAction = $this->formatActionName($oToken->getAction());

		$oController->initialize($oToken->getParameters());

		$oView = $oController->$sAction();

		if($oView instanceof Rapide_View_Interface)
			$oView->display();

		$oNextToken = $oController->getNextToken();

		if($oNextToken instanceof Rapide_Dispatcher_Token_Interface)
			return $oNextToken;
		else
			return false;
	}

	/**
	 * Check if token is dispatchable
	 *
	 * @param Rapide_Dispatcher_Token_Interface $oToken
	 * @return bool
	 */
	public function isDispatchable(Rapide_Dispatcher_Token_Interface $oToken)
	{
		$sControllerClass = $this->formatControllerName($oToken->getController());
	
		try
		{
			$oController = new $sControllerClass;
			$sAction = $this->formatActionName($oToken->getAction());
	
			return method_exists($oController, $sAction);
		}
		catch(Rapide_Exception $e)
		{
			return false;
		}
	}

	/**
	 * Get current token
	 *
	 * @return Rapide_Dispatcher_Token_Interface
	 */
	public function getCurrentToken()
	{
		return $this->_oToken;
	}

	/**
	 * Format valid name of controller's class
	 *
	 * @param unknown_type $sController
	 * @return string
	 */
	public function formatControllerName($sController)
	{
		return 'Controller_' . ucfirst($sController);
	}

	/**
	 * Format valid name of action
	 *
	 * @param string $sAction
	 * @return string
	 */
	public function formatActionName($sAction)
	{
		return $sAction . 'Action';
	}
}

?>